#import <errno.h>
#import <stdlib.h>
#import <string.h>

#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSUserDefaults.h>
#import <UIKit/UIKit.h>

#import "Application.h"
#import "PreferencesView.h"
#import "MediaPanel.h"
#import "TVPanel.h"
#import "NumericPanel.h"
#import "PadPanel.h"
#import "KeyboardPanel.h"
#import "WinRemoconProtocol.h"

typedef enum
{
	UIStatusBarStyleDefault,
	UIStatusBarStyleBlackTranslucent,
	UIStatusBarStyleBlackOpaque
} UIStatusBarStyle;

typedef enum {
   UIDeviceOrientationUnknown,
   UIDeviceOrientationPortrait,
   UIDeviceOrientationPortraitUpsideDown,
   UIDeviceOrientationLandscapeLeft,
   UIDeviceOrientationLandscapeRight,
   UIDeviceOrientationFaceUp,
   UIDeviceOrientationFaceDown
} UIDeviceOrientation;

typedef enum {
   UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
   UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
   UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeLeft,
   UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeRight
} UIInterfaceOrientation;

@implementation Application

+ (void)initialize
{
	NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
	[defaultValues setValue:[NSNumber numberWithInt:0] forKey:@"last_panel_index"];
	[defaultValues setValue:[NSNumber numberWithInt:0] forKey:@"host_count"];
	[defaultValues setValue:@"192.168.0.2:7378" forKey:@"current_host"];
	[defaultValues setValue:[NSNumber numberWithBool:YES] forKey:@"enable_click_sound"];
	[defaultValues setValue:[NSNumber numberWithBool:YES] forKey:@"enable_pad_panel"];
	[defaultValues setValue:[NSNumber numberWithBool:YES] forKey:@"enable_media_panel"];
	[defaultValues setValue:[NSNumber numberWithBool:YES] forKey:@"enable_tv_panel"];
	[defaultValues setValue:[NSNumber numberWithBool:YES] forKey:@"enable_numeric_panel"];
	[defaultValues setValue:[NSNumber numberWithBool:YES] forKey:@"enable_keyboard_panel"];
	[defaultValues setValue:[NSNumber numberWithBool:NO] forKey:@"mouse_move_absolute"];
	[defaultValues setValue:[NSNumber numberWithBool:NO] forKey:@"mouse_rotate_landscape"];
	[defaultValues setValue:[NSNumber numberWithFloat:1.0] forKey:@"mouse_accel"];
	[defaultValues setValue:[NSNumber numberWithFloat:24.0] forKey:@"text_font_size"];
	[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
	defaults = [NSUserDefaults standardUserDefaults];

	// socket
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	addr.sin_family = AF_INET;
	int so_broadcast = 1;
	setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so_broadcast, sizeof so_broadcast);
	
	// set last host
	[self setHost];
	
	// frame rect
	CGRect frame = [[UIScreen mainScreen] bounds];
	frame.size.height -= 20;
	CGSize barSize = CGSizeMake(320, 49);
	CGRect contentFrame = CGRectMake(0.0, 0.0, frame.size.width, frame.size.height - barSize.height);
	
	// content panels
	mediaPanel = [[MediaPanel alloc] initWithFrame:contentFrame];
	[mediaPanel setDelegate:self];
	
	tvPanel = [[TVPanel alloc] initWithFrame:contentFrame];
	[tvPanel setDelegate:self];
	
	numericPanel = [[NumericPanel alloc] initWithFrame:contentFrame];
	[numericPanel setDelegate:self];
	
	padPanel = [[PadPanel alloc] initWithFrame:contentFrame];
	[padPanel setDelegate: self];
	
	keyboardPanel = [[KeyboardPanel alloc] initWithFrame:contentFrame];
	[keyboardPanel setDelegate:self];
	
	prefs = [[PreferencesView alloc] initWithFrame:contentFrame];
	
	// content view
	content = [[UITransitionView alloc] initWithFrame:contentFrame];
	[content setBackgroundColor:[UIColor blackColor]];
	
	// tab bar
	currentTab = TabItemLast;
	panelLocked = NO;
	[self setStatusBarStyle:UIStatusBarStyleBlackOpaque];
	
	items = [[NSMutableArray alloc] initWithCapacity:6];
	if ([defaults boolForKey:@"enable_pad_panel"])
		[items addObject:[[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Pad", nil) image:[UIImage imageNamed:@"Pad.png"] tag:TabItemPad] autorelease]];
	if ([defaults boolForKey:@"enable_media_panel"])
		[items addObject:[[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Media", nil) image:[UIImage imageNamed:@"Media.png"] tag:TabItemMedia] autorelease]];
	if ([defaults boolForKey:@"enable_tv_panel"])
		[items addObject:[[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"TV", nil) image:[UIImage imageNamed:@"TV.png"] tag:TabItemTV] autorelease]];
	if ([defaults boolForKey:@"enable_numeric_panel"])
		[items addObject:[[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Numeric", nil) image:[UIImage imageNamed:@"Numeric.png"] tag:TabItemNumeric] autorelease]];
	if ([defaults boolForKey:@"enable_keyboard_panel"])
		[items addObject:[[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Keyboard", nil) image:[UIImage imageNamed:@"Keyboard.png"] tag:TabItemKeyboard] autorelease]];
	[items addObject:[[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Prefs", nil) image:[UIImage imageNamed:@"Preferences.png"] tag:TabItemPreferences] autorelease]];
	
	tabBar = [[UITabBar alloc] initWithFrame:CGRectMake(0.0, frame.size.height - barSize.height, frame.size.width, barSize.height)];
	[tabBar setDelegate:self];
	[tabBar setItems:items];	// UITabBar.items increase retain count?
	[tabBar setBackgroundColor:[UIColor blackColor]];
	{
		int index = [[NSUserDefaults standardUserDefaults] integerForKey: @"last_panel_index"];
		if (0 <= index && index < [items count])
		{
			[tabBar setSelectedItem:[items objectAtIndex:index]];
			[self tabBar:tabBar didSelectItem:[items objectAtIndex:index]];
		}
		else
		{
			[tabBar setSelectedItem:[items objectAtIndex:0]];
			[self tabBar:tabBar didSelectItem:[items objectAtIndex:0]];
		}
	}
	
	// whole view
	view = [[UIView alloc] initWithFrame:frame];
	[view setBackgroundColor:[UIColor whiteColor]];
	[view addSubview:content];
	[view addSubview:tabBar];
	
	// create window and show
	frame.origin.y = 20;
	window = [[UIWindow alloc] initWithFrame:frame];
	[window setContentView:view];
	[window makeKeyAndVisible];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
	close(socket);
	[prefs save];
}

- (void)dealloc
{
	[tabBar release];
	[items release];
	[content release];
	[keyboardPanel release];
	[padPanel release];
	[numericPanel release];
	[tvPanel release];
	[mediaPanel release];
	[view release];
	[window release];
	
	[super dealloc];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
	return YES;
}

- (void)setHost
{
	NSArray *hostTokens = [[defaults stringForKey: @"current_host"] componentsSeparatedByString: @":"];
	if ([hostTokens count] == 2)
	{
		addr.sin_port = htons([[hostTokens objectAtIndex: 1] intValue]);
		addr.sin_addr.s_addr = inet_addr([[hostTokens objectAtIndex: 0] cStringUsingEncoding: NSASCIIStringEncoding]);
	}
	[self activateCurrentHost];
}

/*
	同じタブを選択しても呼び出される
*/
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
	NSLog(@"%d to %d", currentTab, [item tag]);
	
	UIView *toView = nil;
	
	if (currentTab == TabItemPreferences)	// 設定の適用
	{
		[prefs save];
		[self setHost];
	}
	
	switch ([item tag])
	{
 		case TabItemMedia:	toView = mediaPanel;	break;
		case TabItemTV:	toView = tvPanel;	break;
		case TabItemNumeric:	toView = numericPanel;	break;
		case TabItemPad:	toView = padPanel;	break;
		case TabItemKeyboard:	toView = keyboardPanel;	break;
		case TabItemPreferences:	toView = prefs;	break;
		default:	break;
	}
	
	if (currentTab == [item tag])
	{
		if (panelLocked)
		{
			for (int i = 0; i != [items count]; ++i)
				[[items objectAtIndex:i] setEnabled:YES];
			panelLocked = NO;
		}
		else
		{
			for (int i = 0; i != [items count]; ++i)
			{
				UITabBarItem *item = [items objectAtIndex:i];
				if ([item tag] == currentTab)	continue;
				[item setEnabled:NO];
			}
			panelLocked = YES;
		}
	}
	
	[[NSUserDefaults standardUserDefaults] setInteger:(currentTab = [item tag]) forKey: @"last_panel_index"];
	if (toView)	[content transition:0 toView:toView];
}

- (void)activateCurrentHost
{
	unsigned char data[1];
	data[0] = WR_NOOP;
	sendto(sock, data, sizeof data / sizeof(unsigned char), 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseMoveAbsolute: (CGPoint)p
{
	if (![[NSUserDefaults standardUserDefaults] boolForKey: @"mouse_move_absolute"])	return;
	
	unsigned char data[5];
	unsigned short *dp = (unsigned short *)&data[1];
	if ([[NSUserDefaults standardUserDefaults] boolForKey: @"mouse_rotate_landscape"])
	{
		*dp++ = htons((unsigned short)p.y);
		*dp = htons((unsigned short)USHRT_MAX - p.x);
	}
	else
	{
		*dp++ = htons((unsigned short)p.x);
		*dp = htons((unsigned short)p.y);
	}
	data[0] = WR_MOUSE_MOVE_ABSOLUTE_WORD;
	
	sendto(sock, data, 5, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseMoveRelative: (CGPoint)d
{
	if ([[NSUserDefaults standardUserDefaults] boolForKey: @"mouse_move_absolute"])	return;
	
	unsigned char data[3];
	data[0] = WR_MOUSE_MOVE_RELATIVE;
	if([[NSUserDefaults standardUserDefaults] boolForKey: @"mouse_rotate_landscape"])
	{
		data[1] = (signed char)(d.y * [[NSUserDefaults standardUserDefaults] floatForKey:@"mouse_accel"]);
		data[2] = (signed char)(- d.x * [[NSUserDefaults standardUserDefaults] floatForKey:@"mouse_accel"]);
	}
	else
	{
		data[1] = (signed char)(d.x * [[NSUserDefaults standardUserDefaults] floatForKey:@"mouse_accel"]);
		data[2] = (signed char)(d.y * [[NSUserDefaults standardUserDefaults] floatForKey:@"mouse_accel"]);
	}
	
	sendto(sock, data, 3, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseWheel: (int)rev
{
	unsigned char data[2];
	
	data[0] = WR_MOUSE_WHEEL;
	data[1] = (signed char)rev;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseLeftButtonClick
{
	unsigned char data[2];
	unsigned char flag = WR_MOUSE_LEFT_BUTTON;
	
	data[0] = WR_MOUSE_BUTTON_CLICK;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseLeftButtonPress
{
	unsigned char data[2];
	unsigned char flag = WR_MOUSE_LEFT_BUTTON;
	
	data[0] = WR_MOUSE_BUTTON_PRESS;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseLeftButtonRelease
{
	unsigned char data[2];
	unsigned char flag = WR_MOUSE_LEFT_BUTTON;
	
	data[0] = WR_MOUSE_BUTTON_RELEASE;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseRightButtonClick
{
	unsigned char data[2];
	unsigned char flag = WR_MOUSE_RIGHT_BUTTON;
	
	data[0] = WR_MOUSE_BUTTON_CLICK;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseRightButtonPress
{
	unsigned char data[2];
	unsigned char flag = WR_MOUSE_RIGHT_BUTTON;
	
	data[0] = WR_MOUSE_BUTTON_PRESS;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)mouseRightButtonRelease
{
	unsigned char data[2];
	unsigned char flag = WR_MOUSE_RIGHT_BUTTON;
	
	data[0] = WR_MOUSE_BUTTON_RELEASE;
	data[1] = flag;
	
	sendto(sock, data, 2, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)qtKeyClicked: (int)key
{
	unsigned char data[5];
	
	unsigned long *dp = (unsigned long *)&data[1];
	*dp = htonl((unsigned long)key);
	data[0] = WR_KEY_CLICK_QT;
	
	sendto(sock, data, sizeof data, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)qtKeyPressed: (int)key
{
	unsigned char data[5];
	
	unsigned long *dp = (unsigned long *)&data[1];
	*dp = htonl((unsigned long)key);
	data[0] = WR_KEY_PRESS_QT;
	
	sendto(sock, data, sizeof data, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)qtKeyReleased: (int)key
{
	unsigned char data[5];
	
	unsigned long *dp = (unsigned long *)&data[1];
	*dp = htonl((unsigned long)key);
	data[0] = WR_KEY_RELEASE_QT;
	
	sendto(sock, data, sizeof data, 0, (struct sockaddr *)&addr, sizeof(addr));
}

- (void)sendingTextRequested:(NSString *)text
{
	unsigned char data[[text lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1];
	data[0] = WR_TEXT;
	strcpy(data + 1, [text cStringUsingEncoding:NSUTF8StringEncoding]);
	sendto(sock, data, sizeof(data), 0, (struct sockaddr *)&addr, sizeof(addr));
}

@end
